# -*- coding: utf-8 -*-

"""
generate url request functions based on configurations

A config is like follows:
1. url a unicode string
2. headers dict
3. parameters dict
4. method "GET" "POST" "HEAD" etc.
5. body a unicode string
"""

from __future__ import unicode_literals
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import re
import logging
from six.moves.urllib import request, parse

from typing import Text, Dict


RE_PARAM = re.compile(r'{{([_A-Za-z]\w*)}}')


def find_parameters(text):
    """
    find parameters in the format of {{parameter}}
    :text: input text
    :return: a tuple of all parameters
    """
    return RE_PARAM.findall(text)


def replace_parameters(text, params):  # type: (Text, Dict) -> Text
    """
    replace the parameters in a text
    :param text: a unicode string
    :param params: dict of parameters
    :return: text with parameters replaced
    """
    if text:
        ps = find_parameters(text)
        for p in ps:
            if p not in params:
                raise Exception("Parameter {0} is required but not provided in code!".format(p))
            text = text.replace("{{{0}}}".format(p), params[p])
    return text


def generate_request_by_config(url, method="GET", raw_parameters=None, raw_headers=None, raw_body=None):
    def __request__(**kwargs):
        parameters = {}
        if raw_parameters:
            for k, v in raw_parameters.items():
                parameters[k] = replace_parameters(v, kwargs).encode("utf-8")

        full_url = url
        if parameters:
            full_url += "?" + parse.urlencode(parameters)

        headers = {}
        if raw_headers:
            for k, v in raw_headers.items():
                headers[k] = replace_parameters(v, kwargs).encode("utf-8")

        body = None
        if raw_body:
            body = replace_parameters(raw_body, kwargs).encode("utf-8")

        req = request.Request(full_url, data=body, headers=headers)
        req.get_method = lambda: method

        try:
            res = request.urlopen(req)
            return res.read().decode("utf-8")
        except Exception as e:
            logging.warn(e)

    return __request__
